We've added a new session, LoanDao. It essentially provides a few queries dealing with loans such as finding all overdue books or finding all patrons with overdue books. LoanDao.java
packagesession;importjava.util.Date;importjava.util.List;importjavax.persistence.NoResultException;importentity.Book;importentity.Loan;importentity.Patron;/**
* Provide some basic queries focused around the Loan object. These queries
* could have been placed in either the PatronDao or BookDao. However, neither
* seemed like quite the right place so we created this new Dao.
*/publicclass LoanDao extends BaseDao {/**
* Given a book id, find the associated loan or return null if none found.
*
* @param bookId
* Id of book on loan
*
* @return Loan object that holds onto bookId
*/public Loan getLoanFor(Long bookId){try{return(Loan) getEm().createNamedQuery("Loan.byBookId")
.setParameter("bookId", bookId).getSingleResult();}catch(NoResultException e){returnnull;}}publicvoid remove(final Loan l){
getEm().remove(l);}/**
* Return books that are due after the compareDate.
*
* @param compareDate
* If a book's due date is after compareDate, then it is included
* in the list. Note that this named query uses projection. Have
* a look at Loan.java.
*
* @return a list of all the books that were due after this date.
*/
@SuppressWarnings("unchecked")publicList<Book> listAllOverdueBooks(finalDate compareDate){return getEm().createNamedQuery("Loan.overdueBooks").setParameter("date", compareDate).getResultList();}/**
* Essentially the same query as listAllOverdueBooks but we return the
* Patrons instead of the books. This method uses a named query that uses
* projection.
*
* @param compareDate
* If a patron has at least one book that was due after the
* compare date, include them.
*
* @return A list of the patrons with at least one overdue book
*/
@SuppressWarnings("unchecked")publicList<Patron> listAllPatronsWithOverdueBooks(finalDate compareDate){return getEm().createNamedQuery("Loan.patronsWithOverdueBooks")
.setParameter("date", compareDate).getResultList();}/**
* Return all books on loan to the provided patron id.
*
* @param patronId
* If patron id is invalid, this method will not notice it.
*
* @return Zero or more books on loan to the patron in question
*/
@SuppressWarnings("unchecked")publicList<Book> listBooksOnLoanTo(finalLong patronId){return getEm().createNamedQuery("Loan.booksLoanedTo").setParameter("patronId", patronId).getResultList();}}
Library.java
packagesession;importjava.util.Date;importjava.util.List;importjavax.persistence.EntityNotFoundException;importentity.Address;importentity.Author;importentity.Book;importentity.Loan;importentity.Patron;importexception.BookAlreadyCheckedOut;importexception.BookNotCheckedOut;importexception.PatronHasFines;/**
* This class provides a basic facade to the library system. If we had a user
* interface, it would interact with this object rather than dealing with all of
* the underlying Daos.
*/publicclass Library {private BookDao bookDao;private PatronDao patronDao;private LoanDao loanDao;public BookDao getBookDao(){return bookDao;}publicvoid setBookDao(final BookDao bookDao){this.bookDao = bookDao;}public PatronDao getPatronDao(){return patronDao;}publicvoid setPatronDao(final PatronDao patronDao){this.patronDao = patronDao;}public LoanDao getLoanDao(){return loanDao;}publicvoid setLoanDao(final LoanDao loanDao){this.loanDao = loanDao;}publicBook createBook(finalString title, finalString isbn,
finalDate date, final Author a1, final Author a2){return getBookDao().create(title, isbn, date, a1, a2);}publicList<Book> findBookByIsbn(String isbn){return getBookDao().findByIsbn(isbn);}public Patron createPatron(finalString patronId, finalString fname,
finalString lname, finalString phoneNumber, final Address a){return getPatronDao().createPatron(fname, lname, phoneNumber, a);}public Patron findPatronById(finalLong id){final Patron p = getPatronDao().retrieve(id);if(p == null){thrownew EntityNotFoundException(String.format("Patron with id: %d does not exist", id));}return p;}publicBook findBookById(Long id){finalBook b = getBookDao().findById(id);if(b == null){thrownew EntityNotFoundException(String.format("Book with Id:%d does not exist", id));}return b;}publicvoid returnBook(finalDate checkinDate, finalLong... bookIds){for(Long bookId : bookIds){final Loan l = getLoanDao().getLoanFor(bookId);if(l == null){thrownew BookNotCheckedOut(bookId);}
l.checkin(checkinDate);
getLoanDao().remove(l);}}publicvoid checkout(finalLong patronId, finalDate checkoutDate,
finalLong... bookIds){final Patron p = findPatronById(patronId);double totalFines = p.calculateTotalFines();if(totalFines > 0.0d){thrownew PatronHasFines(totalFines);}for(Long id : bookIds){finalBook b = findBookById(id);if(b.isCheckedOut()){thrownew BookAlreadyCheckedOut(id);}
p.checkout(b, checkoutDate);}}publicList<Book> listBooksOnLoanTo(finalLong patronId){return getLoanDao().listBooksOnLoanTo(patronId);}publicList<Book> findAllOverdueBooks(finalDate compareDate){return getLoanDao().listAllOverdueBooks(compareDate);}publicList<Patron> findAllPatronsWithOverdueBooks(finalDate compareDate){return getLoanDao().listAllPatronsWithOverdueBooks(compareDate);}publicdouble calculateTotalFinesFor(finalLong patronId){return getPatronDao().retrieve(patronId).calculateTotalFines();}publicdouble tenderFine(finalLong patronId, double amountTendered){final Patron p = getPatronDao().retrieve(patronId);return p.pay(amountTendered);}}
LoanDao.java
Library.java